网站导航:首页开源项目 USB开源项目:Easy USB 51 Programer  

目录导航

   
  1、项目简介
USB开发基础
1、USB接口的优点及开发难易度
2、USB设备的开发流程
3、USB接口芯片(USB控制器)的选择
4、了解USB的通讯过程
5、USB命令(请求)和USB描述符
6、实例讲解USB的枚举(配置)过程
准备工作
1、需要哪些工具
2、电路原理图
3、手工制作您的电路板
4、测试您的硬件
HID设备类
1、让PC机找到我们的硬件
2、如何成为一个HID设备(模拟鼠标)
3、如何成为一个HID设备(模拟键盘)
4、如何与HID设备通讯(一)
5、如何与HID设备通讯(二)
6、51编程器的实现
Windows USB 驱动程序(自定义设备)
1、Windows驱动开发基础
2、开发环境配置
3、第一个实例-Hello Wdm(一)
4、第一个实例-Hello Wdm(二)
5、真正的实例—驱动我们的实验板
6、真正的实例—测试驱动程序
7、真正的实例—控制LED及读取按键状态
8、如何编写应用程序
   

相关产品    淘宝网店
     
 

 
  更多...  
 
 
如何与HID设备通讯(二) 查看/参与此开源项目相关讨论
 

三、读写HID设备的步骤

  读写HID设备步骤如下:

①、得到系统HID设备结构数组指针
②、对设备进行遍历
③、得到指定HID设备的句柄
④、readfile/writefile进行读写

  下面分别对各步骤及其所涉及的相关API函数进行介绍。

1、得到设备句柄:这步用到的两面个主要API函数原型为:

A、通过以下函数

 
  1. VOID  HidD_GetHidGuid(OUT LPGUID  HidGuid    );  

得到HID设备的GUID。

B、再通过以下函数

 
  1. HDEVINFO SetupDiGetClassDevs(   
  2.   CONST LPGUID ClassGuid,    
  3.   PCTSTR Enumerator,    
  4.   HWND hwndParent,    
  5.   DWORD Flags   
  6. );  

取得HID设备结构数组指针,以便下一步利用这个数组对所有HID设备进行遍列。

2、对设备进行遍历:遍历过程如下

A、首先执行以下函数:

 
  1. WINSETUPAPI BOOL WINAPI  SetupDiEnumDeviceInterfaces(   
  2.     IN HDEVINFO  DeviceInfoSet,   
  3.     IN PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL,   
  4.     IN LPGUID  InterfaceClassGuid,   
  5.     IN DWORD  MemberIndex,   
  6.     OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData);  

运行此函数的主要目的是取得第一个参数DeviceInfoSet的填充值,又将此值作为以下函数

 
  1. BOOL SetupDiGetDeviceInterfaceDetail(   
  2.     HDEVINFO DeviceInfoSet,    
  3.     PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,    
  4.     PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,    
  5.     DWORD DeviceInterfaceDetailDataSize,    
  6.     PDWORD RequiredSize,    
  7.     PSP_DEVINFO_DATA DeviceInfoData);   

的第一个参数,以便取得这个函数的第三个参数DeviceInterfaceDetailData的填充值,然后利用这个值传递给CreateFile函数,此时CreateFile会返回一个指向HID设备的句柄,再根据以下函数

 
  1. BOOLEAN  HidD_GetAttributes(   
  2.     IN HANDLE  HidDeviceObject,   
  3.     OUT PHIDD_ATTRIBUTES  Attributes   
  4.     );  

取得此HID设备的属性(第二个参数的填充值),然后判断属性里的PID(Attributes->ProductID)和VID(Attributes->VendorID)是否是我们要查找的设备的PID和VID。PID和VID在下位机固件代码的设备描述符里提供(设备描述里的idProduct域和idVendor,参考百合电子工作室发表的文章《USB开发基础--USB命令(请求)和USB描述符》一文中表4),当然您也可以通过一些工具查询得到PID和VID,您可以到USB组织官方网站www.usb.org下载这类工具。

3、根据得到的设备句柄利用ReadFile和WriteFile对设备进行读写操作。

  百合电子工作室已经将以上步骤封装成了一个HID类(参考了其它一些实例代码),它能实现对指定PID和VID设备的查找,并实现了数据收发功能,同时具有设备拨插检测通知功能。点击这里下载

下面用实例说明如何使用这个类。

 四、读写HID设备实例

实例 1

1、找开Visual C++ 6.0,新建一基于MFC的工程名为:Easy USB 51 Programer Test1。

2、MFC AppWizard Step 1对话框中选择基于对话框的应用程序,然后点“Finish”按钮,如图所示:

3、创建3个静态文本标签(Static Text),文本内容分别为:Write、Read和Message;创建两个文本框和一个列表框,ID分别为:IDC_EDIT_TX、IDC_EDIT_RX和IDC_LIST_MESSAGE;两个按钮ID和文本分别为:IDC_BTN_WRITE(Write)和IDCANCEL(Exit)。界面如下:

4、添加控件所对应的变量,如下图所示:

5、将Hid.c和Hid.h导入工程,并将“要用到的windows ddk里的几个文件”文件夹内的文件复制到工程所在目录,在Procect->Settings->Link页的“Object/Library moudles”设置中添加“hid.lib setupapi.lib”,如下图所示:

6、在stdafx.h文件中包含头文件语句前添加:#define WINVER  0x0500

7、修改Hid.c中的PID和VID宏定义来设置需要访问的HID设备,此处的PID和VID值分别为0x0666和0x0471:

 
  1. #define VID 0x0471   
  2. #define PID 0x0666  

8、在CEasyUSB51ProgramerTest1Dlg类中添加成员变量m_MyHidDevice,其定义如下

 
  1. CHid m_MyHidDevice;  

当然您得包含头文件Hid.h。

9、在CEasyUSB51ProgramerTest1Dlg类的OnInitDialog函数中添加如下语句:

 
  1. m_MyHidDevice.m_hParentWnd = (HANDLE*) this->GetSafeHwnd( );   
  2. if(m_MyHidDevice.FindHid())     //找到指定HID设备   
  3. {   
  4.     m_ctrlMessage.InsertString(-1,"My hid device detected");   
  5. }   
  6. else                            //没有找到指定HID设备   
  7. {   
  8.     m_ctrlMessage.InsertString(-1,"My hid device not detected");   
  9.     m_ctrlWrite.EnableWindow(FALSE);    //禁用"write"按钮   
  10. }  

10、在CEasyUSB51ProgramerTest1Dlg的消息映射中(“BEGIN_MESSAGE_MAP(CEasyUSB51ProgramerTest1Dlg, CDialog)” 与 “END_MESSAGE_MAP()”之间)添加如下代码:

 
  1. ON_MESSAGE(WM_DEVICECHANGE, OnDeviceChange)  

11、在CEasyUSB51ProgramerTest1Dlg类中添加成员函数:

 
  1. LRESULT OnDeviceChange(WPARAM wParam, LPARAM lParam);  

12、成员函数OnDeviceChange的结构如下:

 
  1. LRESULT CEasyUSB51ProgramerTest1Dlg::OnDeviceChange(WPARAM wParam, LPARAM lParam)   
  2. {   
  3.        
  4.     /* take the appropriate action for the message */  
  5.     switch(LOWORD(wParam))    
  6.     {   
  7.            
  8.         /* HID device arrival */  
  9.         case DBT_DEVICEARRIVAL:   
  10.         {   
  11.             /* try to open a handle to the device */  
  12.             if(m_MyHidDevice.FindHid()) /*此处必须调用FindHid()判断是否是“ 我”的HID设备插入USB口*/  
  13.             {   
  14.                 /*检测到指定的HID设备插入USB口*/  
  15.                 /*您在这里可以添加其它功能代码*/                 
  16.             }   
  17.             break;   
  18.         }   
  19.   
  20.         /* HID device removal */  
  21.         case DBT_DEVICEREMOVECOMPLETE:   
  22.         {   
  23.             if(!m_MyHidDevice.FindHid())    /*此处必须调用FindHid()判断是否是“ 我”的HID设备拨出USB口*/  
  24.             {   
  25.                 /*检测到指定的HID设备拨出USB口*/  
  26.                 /*您在这里可以添加其它功能代码*/                 
  27.             }   
  28.             break;   
  29.         }   
  30.     }   
  31.   
  32.     return true;   
  33. }  

13、这里为了实现在Message信息框里显示HID设备的拨插操作,现对OnDeviceChange函数作如下填充:

 
  1. LRESULT CEasyUSB51ProgramerTest1Dlg::OnDeviceChange(WPARAM wParam, LPARAM lParam)   
  2. {   
  3.        
  4.     /* take the appropriate action for the message */  
  5.     switch(LOWORD(wParam))    
  6.     {   
  7.            
  8.         /* HID device arrival */  
  9.         case DBT_DEVICEARRIVAL:   
  10.         {   
  11.             /* try to open a handle to the device */  
  12.             if(m_MyHidDevice.FindHid()) /*此处必须调用FindHid()判断是否是“ 我”的HID设备插入USB口*/  
  13.             {   
  14.                 /*检测到指定的HID设备插入USB口*/  
  15.                 /*您在这里可以添加其它功能代码*/  
  16.                 unsigned short nIndex   = m_ctrlMessage.InsertString(-1,"My hid device detected");   
  17.                 m_ctrlMessage.SetCurSel(nIndex);    //流动信息窗口   
  18.                 m_ctrlWrite.EnableWindow(TRUE);     //启用"write"按钮   
  19.             }   
  20.             break;   
  21.         }   
  22.   
  23.         /* HID device removal */  
  24.         case DBT_DEVICEREMOVECOMPLETE:   
  25.         {   
  26.             if(!m_MyHidDevice.FindHid())    /*此处必须调用FindHid()判断是否是“ 我”的HID设备拨出USB口*/  
  27.             {   
  28.                 /*检测到指定的HID设备拨出USB口*/  
  29.                 /*您在这里可以添加其它功能代码*/  
  30.                 unsigned short nIndex   = m_ctrlMessage.InsertString(-1,"My hid device removed");   
  31.                 m_ctrlMessage.SetCurSel(nIndex);    //流动信息窗口   
  32.                 m_ctrlWrite.EnableWindow(FALSE);    //禁用"write"按钮   
  33.             }   
  34.             break;   
  35.         }   
  36.     }   
  37.   
  38.     return true;   
  39. }  

 14、对HID的读写可通过Hid类的成员函数WriteHid和ReadHid。以下是"write"按钮的响应函数,实现对HID设备的读写操作:

 
  1. void CEasyUSB51ProgramerTest1Dlg::OnBtnWrite()    
  2. {   
  3.     unsigned char ucTxBuffer[64];   //发送缓冲   
  4.     unsigned char ucRxBuffer[64];   //接收缓冲   
  5.   
  6.     UpdateData(TRUE);   
  7.   
  8.     //判断发送框中内容是否超过64字节   
  9.     if(m_strTx.GetLength()>64)   
  10.     {   
  11.         AfxMessageBox("发送字节数不能超过64个字节");   
  12.     }   
  13.   
  14.     //准备发送缓冲区中的内容   
  15.     for(int i=0; i<64 ; i++)   
  16.     {   
  17.         if(i <= (m_strTx.GetLength()-1) )   
  18.             ucTxBuffer[i]   = m_strTx.GetAt(i);   
  19.         else  
  20.             ucTxBuffer[i]   = 0;   
  21.     }   
  22.   
  23.     //写操作   
  24.     m_MyHidDevice.WriteHid(ucTxBuffer,64);   
  25.     //读操作   
  26.     m_MyHidDevice.ReadHid(ucRxBuffer,64);   
  27.   
  28.     m_strRx     = ucRxBuffer;   
  29.     UpdateData(FALSE);   
  30. }  

完成后的实际效果:

下载程序

下载源代码

实例 2

  此例子需要用到扩展板:EXT-BOARD-A。实现功能为通过上位机设定 EXT-BOARD-A 上的8个发光二极管状态。

 1、命令及数据定义

  下位机已经规定了每帧数据的长度为64个字节,我们现在需要对每一个字节的含义作出定义。在这个实例中,我们可作如下规定:每帧数据前5个字节为命令,命令后面紧跟数据(从第6个字节开始)。命令为ASCII编码,在此实例中只有一个命令“ENLED”,代表设备LED状态。命令后面的一个字节为数据,代表D0~D7八个LED的状态,后面的字节无意义。

2、修改下位机程序

  修改main.c文件,其内容如下:

 
  1. /********************************Copyright (c)**************************************************  
  2. **                               百合电子工作室  
  3. **                                 
  4. **                                  
  5. **  
  6. **                            http://www.baiheee.com  
  7. **  
  8. ** 文   件   名: main.c  
  9. ** 最后修改日期: 2008年12月25日  
  10. ** 描        述: 用户应用程序  
  11. ** 版          本: V6.0  
  12. **********************************************************************************************************/  
  13.   
  14. //#include <at89x52.h>   
  15. #include <reg51.h>   
  16. #include "D12Config.h"   
  17. #include "Descriptor.h"   
  18. #include "Chap_9.h"   
  19. #include "D12Driver.h"   
  20. #include <string.h>   
  21.   
  22. main()   
  23. {      
  24.     unsigned char ucLedState;   
  25.        
  26.     if (Init_D12()!=0)                  //初始化D12   
  27.         return;                         //如果初始化不成功,返回   
  28.        
  29.     IT0 = 0;                            //外部中断0为电平触发方式   
  30.        
  31.     EX0 = 1;                            //开外部中断0   
  32.     PX0 = 0;                            //设置外部中断0中断优先级   
  33.     EA = 1;                             //开80C51总中断    
  34.        
  35.     while(1)   
  36.     {   
  37.         usbserve();                     //处理USB事件   
  38.         if(bEPPflags.bits.configuration)       
  39.         {       
  40.             //在这里添加端点操作代码     
  41.                
  42.             if(bEPPflags.bits.ep2_rxdone )  //主端点接收到数据(从主机发往设备的数据)       
  43.             {       
  44.                 bEPPflags.bits.ep2_rxdone       = 0;           
  45.                    
  46.                 //判断是否是 ENLED 命令(EpBuf的前5个字节为”ENLED“)            
  47.                 if(strncmp("ENLED",EpBuf,5)==0)   
  48.                 {   
  49.                     //取得LED状态设定值   
  50.                     ucLedState  = EpBuf[5];   
  51.                        
  52.                     //设定LED状态   
  53.                     P0  = ucLedState;   
  54.                 }                          
  55.             }        
  56.         }     
  57.     }   
  58. }   

 点击这里下载修改好的源代码

 3、上位机程序

  通过实例1的学习,其实上位机程序的编写非常简单,所以在这里只贴出源代码。

                                           
            

              上位机界面                                               LED的状态由上位机控制

 下载程序

 下载源代码

 
 
 
本站程序由百合电子工作室开发和维护
Copyright @ baihe electric studio
渝ICP备09006681号-4